﻿#region Imports

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Xml;
using System.Xml.Xsl;
using System.Xml.XPath;
using System.Diagnostics;
using System.Collections.ObjectModel;
using System.Drawing.Drawing2D;
using System.Threading;
using System.Xml.Serialization;
using System.Windows.Forms.VisualStyles;
using System.Runtime.InteropServices;

using Microsoft.SharePoint.Administration;
using mshtml;
using ColorCode;

using Wilke.SharePoint.Tools.Resources.Miscellaneous;

#endregion

namespace Wilke.SharePoint.Tools
{
    public partial class Main : Form
    {
        private bool formIsLoading = false;
        private bool listIsLoading = false;
        private bool validatingAll = false;
        private bool xmlDocumentReady = false;

        private XmlDocument xmlDocument = null;
        private List<WebConfigModification> appliedWebConfigModifications = new List<WebConfigModification>();
        private List<WebConfigModification> toApplyWebConfigModifications = new List<WebConfigModification>();

        private ListView currentListView = null;
        private List<WebConfigModification> currentWebConfigModifications;

        private int currentIndex;
        private int currentListOffset;

        private bool xmlDocumentError = false;

        private const int SB_HORZ = 0;
        private const int SB_VERT = 1;

        private const int SIF_RANGE = 1;
        private const int SIF_PAGE = 2;
        private const int SIF_POS = 4;
        private const int SIF_DISABLKENOSCROLL = 8;
        private const int SIF_TRACKPOS = 16;
        private const int SIF_ALL = SIF_RANGE | SIF_PAGE | SIF_POS | SIF_DISABLKENOSCROLL | SIF_TRACKPOS;

        [StructLayout(LayoutKind.Sequential)]
        public struct SCROLLINFO
        {
            public Int32 size;
            public Int32 mask;
            public Int32 min;
            public Int32 max;
            public Int32 page;
            public Int32 pos;
            public Int32 trackPos;
        }

        [DllImport("user32")]
        public static extern bool GetScrollInfo(IntPtr handle, int wBar, ref SCROLLINFO scrollInfo);

        [DllImport("user32")]
        public static extern int ShowScrollBar(IntPtr handle, int wBar, int bShow);

        public Main()
        {
            InitializeComponent();
        }

        #region Event Handlers

        private void Main_Load(object sender, EventArgs e)
        {
            formIsLoading = true;

            ClearWebConfigModification();

            #region Load Initial XmlDocument

            webBrowserConfigFile.DocumentText = "<H2>Loading ...</H2>";

            dropDownWebApplications.Text = Constants.MessageWebApplicationsLoading;

            backgroundWorker.RunWorkerAsync();

            #endregion

            PopulateListView(listViewApplied);
            PopulateListView(listViewToApply);

            listView_SizeChanged(listViewApplied, new EventArgs());
            listView_SizeChanged(listViewToApply, new EventArgs());

            listView_Enter(listViewToApply, new EventArgs());

            formIsLoading = false;

            dropDownWebApplications_SelectedIndexChanged(this, new EventArgs());

            this.Text += String.Format(" - {0}", ConfigurationHelper.SharePointVersion);
        }

        private void dropDownWebApplications_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (!formIsLoading)
            {
                if (dropDownWebApplications.SelectedIndex > -1)
                {
                    string webApplicationName = dropDownWebApplications.SelectedItem.ToString();

                    if (radioButtonWebConfig.Checked)
                    {
                        if (!dropDownWebApplications.SelectedItem.ToString().Contains("Error"))
                        {
                            radioButton_CheckedChanged(radioButtonWebConfig, new EventArgs());
                        }
                    }
                    else
                    {
                        radioButtonWebConfig.Checked = true;
                    }
                }
            }
        }

        private void buttonBrowse_Click(object sender, EventArgs e)
        {
            openFileDialog.CheckFileExists = true;
            openFileDialog.DefaultExt = "xml";
            openFileDialog.InitialDirectory = ConfigurationHelper.InetPubPath;
            openFileDialog.FileName = String.Empty;
            openFileDialog.Filter = "Configuration files (*.config)|*.config|Xml documents (*.xml)|*.xml|All files (*.*)|*.*";
            DialogResult dialogResult = openFileDialog.ShowDialog();

            if (dialogResult == DialogResult.OK)
            {
                textBoxXmlDocument.Text = openFileDialog.FileName;
                if (radioButtonXmlDocument.Checked)
                {
                    radioButton_CheckedChanged(radioButtonXmlDocument, new EventArgs());
                }
                else
                {
                    radioButtonXmlDocument.Checked = true;
                }
            }
        }

        private void optionsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OptionsForm optionsForm = new OptionsForm();
            optionsForm.ShowDialog();
        }

        private void radioButton_CheckedChanged(object sender, EventArgs e)
        {
            RadioButton radioButton = sender as RadioButton;

            if (radioButton.Checked)
            {
                try
                {
                    switch (radioButton.Tag.ToString())
                    {
                        case "1":
                            if (dropDownWebApplications.SelectedIndex > -1)
                            {
                                if (!dropDownWebApplications.SelectedItem.ToString().Contains("Error"))
                                {                                   
                                    string webApplicationName = dropDownWebApplications.SelectedItem.ToString();
                                    this.xmlDocument = SharePointUtilites.GetWebConfigFile(webApplicationName);
                                    DisplayXmlDocument(false);                                   
                                }
                            }
                            break;
                        case "2":
                            this.xmlDocument = new XmlDocument();
                            this.xmlDocument.Load(textBoxXmlDocument.Text);
                            DisplayXmlDocument(false);
                            break;
                        case "3":
                            this.xmlDocument = new XmlDocument();
                            this.xmlDocument.LoadXml(Properties.Resources.EmptyXml);
                            DisplayXmlDocument(false);
                            break;
                    }

                    #region Load AutoLookup Values

                    UpdateAutoLookup();

                    #endregion
                }
                catch (Exception exception)
                {
                    ClearXmlDocument(true);
                    SetStatusError(exception.Message);
                }
            }
        }

        private void textBoxXmlDocument_TextChanged(object sender, EventArgs e)
        {
            radioButtonXmlDocument.Enabled = textBoxXmlDocument.Text.Length > 0;
        }

        private void statusLabelTimer_Tick(object sender, EventArgs e)
        {
            statusLabel.Text = String.Empty;
            statusLabelTimer.Stop();
        }

        private void listView_SizeChanged(object sender, EventArgs e)
        {
            ListView listView = sender as ListView;
            PictureBox pictureBoxApply = null;
            PictureBox pictureBoxAdd = null;

            listView.Columns[0].Width = listView.Width;
            ShowScrollBar(listView.Handle, 0, 0);

            #region ScrollBar Visible

            SCROLLINFO scrollInfo = new SCROLLINFO();
            scrollInfo.size = Marshal.SizeOf(scrollInfo);
            scrollInfo.mask = SIF_ALL;

            bool test = GetScrollInfo(listViewToApply.Handle, SB_VERT, ref scrollInfo);

            bool scrollBarVisible = listView.Items.Count > 0 && (scrollInfo.page <= scrollInfo.max);

            pictureBoxApply = (PictureBox)this.FindForm().Controls.Find(String.Format("pictureBoxApply{0}", listView.Tag), true)[0];
            pictureBoxAdd = (PictureBox)this.FindForm().Controls.Find(String.Format("pictureBoxAdd{0}", listView.Tag), true)[0];

            pictureBoxApply.Left = (scrollBarVisible) ? listView.Width - 40 : listView.Width - 25;
            pictureBoxAdd.Left = (scrollBarVisible) ? listView.Width - 65 : listView.Width - 50;

            #endregion
        }

        private void listView_Enter(object sender, EventArgs e)
        {
            ListView listView = sender as ListView;

            if (listView.Equals(listViewApplied))
            {
                listViewToApply.SelectedItems.Clear();

                panelApplied.BackColor = Color.SlateBlue;
                panelToApply.BackColor = Color.Transparent;

                currentListOffset = 0;
                currentListView = listViewApplied;
                currentWebConfigModifications = appliedWebConfigModifications;

                if (!panelWebConfigModification.Enabled)
                {
                    panelWebConfigModification.Enabled = true;
                }
            }
            else
            {
                listViewApplied.SelectedItems.Clear();

                panelApplied.BackColor = Color.Transparent;
                panelToApply.BackColor = Color.SlateBlue;

                currentListOffset = 1;
                currentListView = listViewToApply;
                currentWebConfigModifications = toApplyWebConfigModifications;
            }

            currentIndex = -1;

            ClearWebConfigModification();

            if (listView.SelectedIndices.Count > 0)
            {
                if (listView.SelectedItems[0].Tag == null)
                {
                    currentIndex = listView.SelectedIndices[0] - currentListOffset;
                }                

                if (currentIndex > -1)
                {
                    DisplayWebConfigModification(currentWebConfigModifications[currentIndex]);
                }
            }

            listViewApplied.Refresh();
            listViewToApply.Refresh();
        }

        private void listView_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e)
        {
            ListView listView = sender as ListView;
            Rectangle bounds;
            Color startColor;
            Color endColor;
            Brush textColor;
            Bitmap icon = null;
            PictureBox pictureBoxApply = null;
            PictureBox pictureBoxAdd = null;

            bounds = new Rectangle(e.Bounds.Location, e.Bounds.Size);

            if (listView.Equals(currentListView))
            {
                startColor = Color.LightBlue;
                endColor = Color.SteelBlue;
                textColor = Brushes.White;
            }
            else
            {
                startColor = Color.LightGray;
                endColor = Color.DarkGray;
                textColor = Brushes.DimGray;
            }

            pictureBoxApply = (PictureBox)this.FindForm().Controls.Find(String.Format("pictureBoxApply{0}", listView.Tag), true)[0];
            pictureBoxAdd = (PictureBox)this.FindForm().Controls.Find(String.Format("pictureBoxAdd{0}", listView.Tag), true)[0];

            icon = listView.Equals(listViewApplied) ? Properties.Resources.Database : Properties.Resources.Code;

            using (LinearGradientBrush brush = new LinearGradientBrush(e.Bounds, startColor, endColor, LinearGradientMode.Vertical))
            {
                bounds.Offset(-2, 0);
                bounds.Width += 5;
                e.Graphics.FillRectangle(brush, bounds);

                bounds = new Rectangle(e.Bounds.Location, e.Bounds.Size);

                Graphics g = pictureBoxApply.CreateGraphics();
                g.FillRectangle(brush, 0, 0, 22, 22);
                g.DrawImage (pictureBoxApply.Image, 3, 3);

                g = pictureBoxAdd.CreateGraphics();
                g.FillRectangle(brush, 0, 0, 22, 22);
                g.DrawImage(pictureBoxAdd.Image, 3, 3);
            }

            e.Graphics.DrawImage(icon, 3, 3);

            bounds = new Rectangle(e.Bounds.Location, e.Bounds.Size);
            bounds.Offset(25, 2);

            using (Font headerFont = new Font(listView.Font.FontFamily, 9, FontStyle.Bold))
            {
                e.Graphics.DrawString(e.Header.Text, headerFont, textColor, (RectangleF)bounds);
            }
        }

        private void listView_DrawItem(object sender, DrawListViewItemEventArgs e)
        {
            //e.DrawDefault = true;
            ListView listView = sender as ListView;
            Rectangle bounds;
            bool hasFixedItem = false;
            bool proceed = false;

            #region Draw BackGround

            bounds = new Rectangle(e.Bounds.Location, e.Bounds.Size);

            if (e.Item.Selected)
            {
                e.Graphics.FillRectangle(Brushes.Silver, bounds);
            }

            #endregion

            #region Draw Icon

            List<WebConfigModification> webConfigModifications = null;

            if (listView.Equals(listViewApplied))
            {
                webConfigModifications = appliedWebConfigModifications;
                hasFixedItem = false;
            }
            else
            {
                //This list contains amways one item that refers to the 'database' items.
                webConfigModifications = toApplyWebConfigModifications;
                hasFixedItem = true;
            }

            bounds.Offset(10, 1);

            if (e.ItemIndex == 0 && hasFixedItem)
            {
                e.Graphics.DrawImage(Properties.Resources.Database, bounds.X, bounds.Y);
            }
            else
            {
                if (webConfigModifications.Count > 0)
                {
                    int itemIndex = (hasFixedItem) ? e.ItemIndex - 1 : e.ItemIndex;

                    WebConfigModification webConfigModification = webConfigModifications[itemIndex];
                    switch (webConfigModification.Type)
                    {
                        case WebConfigModificationType.EnsureAttribute:
                            e.Graphics.DrawImage(Properties.Resources.Attribute, bounds.X, bounds.Y);
                            break;
                        case WebConfigModificationType.EnsureChildNode:
                            e.Graphics.DrawImage(Properties.Resources.ChildNode, bounds.X, bounds.Y);
                            break;
                        case WebConfigModificationType.EnsureSection:
                            e.Graphics.DrawImage(Properties.Resources.Section, bounds.X, bounds.Y);
                            break;
                    }
                }
            }

            #endregion

            #region Draw CheckBox

            if (listView.Equals(listViewToApply))
            {
                proceed = (e.ItemIndex > 0);
            }
            else
            {
                proceed = true;
            }

            if (proceed)
            {
                bounds = new Rectangle(e.Bounds.Location, e.Bounds.Size);
                bounds.Offset(30, 2);
                CheckBoxRenderer.DrawCheckBox(e.Graphics, bounds.Location, (e.Item.Checked) ? CheckBoxState.CheckedNormal : CheckBoxState.UncheckedNormal);
            }

            #endregion

            #region Draw Text

            bounds = new Rectangle(e.Bounds.Location, e.Bounds.Size);

            if (e.ItemIndex == 0 && hasFixedItem)
            {
                bounds.Offset(30, 1);

                using (Font textFont = new Font(listView.Font.FontFamily, 9, FontStyle.Regular))
                {
                    e.Graphics.DrawString("Remove all, then reapply ", textFont, Brushes.Black, (RectangleF)bounds);

                    bounds.Offset(145, 2);
                    CheckBoxRenderer.DrawCheckBox(e.Graphics, bounds.Location, CheckBoxState.CheckedNormal);

                    bounds.Offset(20, -2);
                    e.Graphics.DrawString("from 'Already Applied'.", textFont, Brushes.Black, (RectangleF)bounds);
                }

                if (listViewApplied.Items.Count > 0)
                {
                    using (Font textFont = new Font(listView.Font.FontFamily, 9, FontStyle.Underline))
                    {
                        bounds.Offset(130, -1);
                        e.Graphics.DrawString("(details)", textFont, Brushes.Blue, (RectangleF)bounds);
                    }
                }
            }
            else
            {
                bounds.Offset(50, 0);

                using (Font textFont = new Font(listView.Font.FontFamily, 9, FontStyle.Regular))
                {
                    e.Graphics.DrawString(e.Item.Text, textFont, Brushes.Black, (RectangleF)bounds);
                }
            }

            #endregion
        }

        private void listView_MouseClick(object sender, MouseEventArgs e)
        {
            ListView listView = sender as ListView;
            ListViewItem listViewItem = listView.HitTest(e.Location).Item;

            if (listViewItem != null)
            {
                Rectangle checkBoxBounds = new Rectangle(30, listViewItem.Bounds.Y, 15, listViewItem.Bounds.Height);

                if (checkBoxBounds.Contains(e.Location))
                {
                    listViewItem.Checked = !listViewItem.Checked;
                }

                if (listViewApplied.Items.Count > 0)
                {
                    #region Click On Details Link

                    if (listView.Equals(listViewToApply) && listViewItem.Index == 0 && Cursor == Cursors.Hand)
                    {
                        WebConfigModificationsForm webConfigModificationsForm = new WebConfigModificationsForm(appliedWebConfigModifications, this.xmlDocument);
                        webConfigModificationsForm.ShowDialog();
                    }

                    #endregion
                }
            }
        }

        private void listView_SelectedIndexChanged(object sender, EventArgs e)
        {
            ListView listView = sender as ListView;

            if (listView.SelectedIndices.Count > 0)
            {
                currentIndex = listView.SelectedIndices[0];

                if (listView.Equals(listViewApplied))
                {
                    if (!panelWebConfigModification.Enabled)
                    {
                        panelWebConfigModification.Enabled = true;
                    }                    
                }
                else
                {
                    if (currentIndex > 0)
                    {
                        currentIndex -= 1;
                        panelWebConfigModification.Enabled = true;
                    }
                    else
                    {
                        panelWebConfigModification.Enabled = false;
                    }
                }

                if (panelWebConfigModification.Enabled && currentIndex > -1)
                {
                    DisplayWebConfigModification(currentWebConfigModifications[currentIndex]);
                }
            }
            else
            {
                ClearWebConfigModification();

                if (!panelWebConfigModification.Enabled)
                {
                    panelWebConfigModification.Enabled = true;
                }
            }
        }

        private void listView_ItemChecked(object sender, ItemCheckedEventArgs e)
        {
            int index = currentIndex;

            if (!listIsLoading)
            {
                ListView listView = sender as ListView;

                try
                {
                    WebConfigModification webConfigModification = currentWebConfigModifications[currentIndex];
                    webConfigModification.Checked = e.Item.Checked;
                    DisplayWebConfigModification(webConfigModification);
                }
                catch (Exception exception)
                {
                    SetStatusError(exception.Message);
                }
            }
        }

        private void listView_ItemDrag(object sender, ItemDragEventArgs e)
        {
            ListViewItem listViewItem = e.Item as ListViewItem;

            //Fixed listviewitem in ToApply listview 
            //has its tag set to 'Fixed'.
            if (listViewItem != null && listViewItem.Tag == null)
            {
                DoDragDrop(e.Item, DragDropEffects.Copy);
            }
        }

        private void listView_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(typeof(ListViewItem)))
            {
                ListViewItem listViewItem = (ListViewItem)e.Data.GetData(typeof(ListViewItem));
                ListView listView = listViewItem.ListView;
                if (!listView.Equals(sender))
                {   
                    e.Effect = DragDropEffects.Copy;
                }
            }
        }

        private void listView_DragDrop(object sender, DragEventArgs e)
        {
            ListView sourceListView = null;
            ListView destinationListView = null;
            List<WebConfigModification> sourceWebConfigModifications = null;
            List<WebConfigModification> destinationWebConfigModifications = null;
            int index = 0;

            if (e.Data.GetDataPresent(typeof(ListViewItem)))
            {
                ListViewItem listViewItem = (ListViewItem)e.Data.GetData(typeof(ListViewItem));
                sourceListView = listViewItem.ListView;

                if (sourceListView != null)
                {
                    if (sourceListView.Equals(listViewApplied))
                    {
                        destinationListView = listViewToApply;
                        sourceWebConfigModifications = appliedWebConfigModifications;
                        destinationWebConfigModifications = toApplyWebConfigModifications;
                        index = listViewItem.Index;
                    }
                    else
                    {
                        destinationListView = listViewApplied;
                        sourceWebConfigModifications = toApplyWebConfigModifications;
                        destinationWebConfigModifications = appliedWebConfigModifications;
                        index = listViewItem.Index - currentListOffset;
                    }

                    WebConfigModification webConfigModification = sourceWebConfigModifications[index].Clone();

                    string key = String.Format("{0}{1}{2}", webConfigModification.Path, webConfigModification.Path.EndsWith("/") ? "" : "/", webConfigModification.Name);

                    if (destinationListView.Items[key] == null)
                    {
                        destinationWebConfigModifications.Add(webConfigModification);
                        PopulateListView(destinationListView);
                    }
                }
            }
        }

        private void listViewApplied_MouseMove(object sender, MouseEventArgs e)
        {
            if (listViewApplied.Items.Count > 0)
            {
                ListView listView = sender as ListView;
                Point point = listView.PointToClient(Cursor.Position);
                ListViewHitTestInfo listViewHitTestInfo = listView.HitTest(point);
                ListViewItem listViewItem = listViewHitTestInfo.Item;

                #region Simulate Details Link Hover

                if (listViewItem != null && listViewItem.Index == 0)
                {
                    Rectangle bounds = new Rectangle(listViewItem.Bounds.Location, listViewItem.Bounds.Size);
                    bounds.Width = 50;
                    bounds.Offset(325, 0);
                    if (bounds.Contains(point))
                    {
                        Cursor = Cursors.Hand;
                    }
                    else
                    {
                        if (Cursor != Cursors.Default)
                        {
                            Cursor = Cursors.Default;
                        }
                    }
                }
                else
                {
                    if (Cursor != Cursors.Default)
                    {
                        Cursor = Cursors.Default;
                    }
                }

                #endregion
            }
        }

        private void buttonModification_Click(object sender, EventArgs e)
        {
            WebConfigModification webConfigModification = null;

            validatingAll = true;

            if (this.ValidateChildren())
            {
                switch (buttonMofication.Text)
                {
                    case "&Add":
                        webConfigModification = new WebConfigModification();
                        webConfigModification.Owner = textBoxOwner.Text;
                        webConfigModification.Sequence = Int32.Parse(textBoxSequence.Text);
                        webConfigModification.Type = (WebConfigModificationType)Enum.Parse(typeof(WebConfigModificationType), dropDownType.Text);
                        webConfigModification.Path = textBoxPath.Text;
                        webConfigModification.Name = textBoxName.Text;
                        webConfigModification.Value = textBoxValue.Text;
                        webConfigModification.Checked = true;
                        webConfigModification.PreviousAttributeValue = String.Empty;
                        currentWebConfigModifications.Add(webConfigModification);
                        currentIndex = currentListView.Items.Count - 1;
                        break;
                    case "&Save":
                        if (currentIndex > -1)
                        {
                            webConfigModification = currentWebConfigModifications[currentIndex];
                            webConfigModification.Owner = textBoxOwner.Text;
                            webConfigModification.Sequence = Int32.Parse(textBoxSequence.Text);
                            webConfigModification.Type = (WebConfigModificationType)Enum.Parse(typeof(WebConfigModificationType), dropDownType.Text);
                            webConfigModification.Path = textBoxPath.Text;
                            webConfigModification.Name = textBoxName.Text;
                            webConfigModification.Value = textBoxValue.Text;
                            webConfigModification.PreviousAttributeValue = textBoxPreviousAttributeValue.Text;
                        }
                        break;
                }

                PopulateCurrentListView();

                currentListView.Items[currentIndex + currentListOffset].Selected = true;

                validatingAll = false;
            }
        }

        private void TextBox_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == '\r')
            {
                SelectNextControl((Control)sender, true, true, true, true);
            }
        }

        private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                e.Result = SharePointUtilites.GetWebApplications();
            }
            catch (Exception exception)
            {
                e.Result = exception;
            }
        }

        private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if ((e.Result as Exception) == null)
            {
                List<string> webApplications = e.Result as List<String>;
                dropDownWebApplications.DataSource = webApplications;
                dropDownWebApplications.Enabled = true;
                radioButton_CheckedChanged(radioButtonWebConfig, new EventArgs());
            }
            else
            {
                Exception exception = e.Result as Exception;
                List<string> items = new List<string>();
                items.Add(Constants.ErrorSharePointNotAvailable);
                dropDownWebApplications.DataSource = items;
                dropDownWebApplications.Enabled = false;
                radioButtonWebConfig.Checked = false;
                radioButtonWebConfig.Enabled = false;
                ClearXmlDocument(true);
                MessageBox.Show(exception.Message);
                SetStatusError(exception.Message);
            }

            xmlDocumentReady = true;
        }

        private void contextMenuListView_Opening(object sender, CancelEventArgs e)
        {
            //Right click on columnHeader is not detected as click event and thus the ListView_Enter
            //event is not triggered. It is this event that sets the current listview.
            ContextMenuStrip contextMenu = sender as ContextMenuStrip;

            listView_Enter(contextMenu.SourceControl, new EventArgs());

            if (currentListView.Equals(listViewApplied))
            {
                if (dropDownWebApplications.Text != Constants.ErrorSharePointNotAvailable && dropDownWebApplications.Text != Constants.MessageWebApplicationsLoading)
                {
                    getFromWebApplicationMenuItem.Text = String.Format("Get from '{0}'", dropDownWebApplications.Text);
                    getFromWebApplicationMenuItem.Visible = true;
                }
                else
                {
                    getFromWebApplicationMenuItem.Visible = false;
                }
            }
            else
            {
                getFromWebApplicationMenuItem.Visible = false;
            }

            if (currentListView.Equals(listViewApplied))
            {
                deleteCurrentMenuItem.Enabled = (currentListView.Items.Count > 0 && currentListView.SelectedIndices.Count > 0);
            }
            else
            {
                if (currentIndex > -1)
                {
                    deleteCurrentMenuItem.Enabled = (currentListView.Items.Count > 0 && currentListView.SelectedIndices.Count > 0);
                }
                else
                {
                    deleteCurrentMenuItem.Enabled = false;
                }
            }
            
            if (currentListView.Equals(listViewApplied))
            {
                saveMenuItem.Enabled = (currentListView.Items.Count > 0);
                applyMenuItem.Enabled = (currentListView.Items.Count > 0);
                clearAllMenuItem.Enabled = (currentListView.Items.Count > 0);
            }
            else
            {
                saveMenuItem.Enabled = (currentListView.Items.Count > 1);
                applyMenuItem.Enabled = (currentListView.Items.Count > 1);
                clearAllMenuItem.Enabled = (currentListView.Items.Count > 1);
            }
        }

        private void clearMenuItem_Click(object sender, EventArgs e)
        {
            DialogResult dialogResult = MessageBox.Show("Clear current list?", "Attention", MessageBoxButtons.OKCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2);
            if (dialogResult == System.Windows.Forms.DialogResult.OK)
            {
                currentWebConfigModifications.Clear();
                PopulateCurrentListView();
            }
        }

        private void listView_HeaderClicked(object sender, ColumnClickEventArgs e)
        {
            listView_Enter(sender, new EventArgs());
        }

        private void textBox_Validating(object sender, CancelEventArgs e)
        {
            TextBox textBox = sender as TextBox;

            if (textBox.Text.Trim().Length == 0)
            {
                errorProvider.SetError(textBox, String.Format("{0} cannot be null.", textBox.Name.Replace("textBox", "")));
                
                if (validatingAll)
                {
                    e.Cancel = true;
                }
            }
            else
            {
                errorProvider.SetError(textBox, String.Empty);
            }
        }

        private void deleteCurrentMenu_Click(object sender, EventArgs e)
        {
            if (currentIndex > -1)
            {
                currentWebConfigModifications.RemoveAt(currentIndex);
                PopulateCurrentListView();
                ClearWebConfigModification();
            }
        }

        private void saveMenuItem_Click(object sender, EventArgs e)
        {
            saveFileDialog.DefaultExt = "xml";
            saveFileDialog.AddExtension = true;
            saveFileDialog.Filter = "Xml documents (*.xml)|*.xml";
            DialogResult dialogResult = saveFileDialog.ShowDialog();

            if (dialogResult == DialogResult.OK)
            {
                XmlSerializer serializer = new XmlSerializer(typeof(List<WebConfigModification>));

                using (FileStream fileStream = File.Open(saveFileDialog.FileName, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite))
                {
                    serializer.Serialize(fileStream, currentWebConfigModifications);
                }
            }
        }

        private void loadMenuItem_Click(object sender, EventArgs e)
        {
            openFileDialog.CheckFileExists = true;
            openFileDialog.DefaultExt = "xml";
            openFileDialog.InitialDirectory = ConfigurationHelper.InetPubPath;
            openFileDialog.FileName = String.Empty;
            openFileDialog.Filter = "Xml documents (*.xml)|*.xml";
            DialogResult dialogResult = openFileDialog.ShowDialog();

            if (dialogResult == DialogResult.OK)
            {
                try
                {
                    XmlSerializer serializer = new XmlSerializer(typeof(List<WebConfigModification>));

                    using (FileStream fileStream = File.Open(openFileDialog.FileName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        currentWebConfigModifications.Clear();
                        currentWebConfigModifications.AddRange((List<WebConfigModification>)serializer.Deserialize(fileStream));
                    }

                    PopulateCurrentListView();
                }
                catch (Exception)
                {
                    SetStatusError("Could not load file.");
                }
            }
        }

        private void buttonCancel_Click(object sender, EventArgs e)
        {
            ClearWebConfigModification();
            errorProvider.SetError(textBoxPath, String.Empty);
            errorProvider.SetError(textBoxName, String.Empty);
            errorProvider.SetError(textBoxValue, String.Empty);
            errorProvider.SetError(textBoxOwner, String.Empty);
        }

        private void linkLabelReload_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            if (radioButtonWebConfig.Checked)
            {
                radioButton_CheckedChanged(radioButtonWebConfig, new EventArgs());
            }
            else if (radioButtonXmlDocument.Checked)
            {
                radioButton_CheckedChanged(radioButtonXmlDocument, new EventArgs());
            }
            else
            {
                radioButton_CheckedChanged(radioButtonEmptyXml, new EventArgs());
            }
        }

        private void applyMenuItem_Click(object sender, EventArgs e)
        {
            if (xmlDocumentError)
            {
                SetStatusError("Can not apply modifications if there was an error during the loading of the xml document.");
                return;
            }

            try
            {
                if (currentListView.Equals(listViewApplied))
                {
                    SharePointUtilites.PreviewWebConfigModifications(ref this.xmlDocument, appliedWebConfigModifications, null);
                }
                else
                {
                    SharePointUtilites.PreviewWebConfigModifications(ref this.xmlDocument, appliedWebConfigModifications, toApplyWebConfigModifications);
                }

                DisplayXmlDocument(true);

                #region Display Selected WebConfigModifation

                if (currentIndex > -1)
                {
                    DisplayWebConfigModification(currentWebConfigModifications[currentIndex]);
                }

                #endregion

                #region Load AutoLookup Values

                UpdateAutoLookup();

                #endregion

                #region Add ToApply to AlreadyApplied list

                foreach (WebConfigModification webConfigModification in toApplyWebConfigModifications)
                {
                    if (webConfigModification.Checked)
                    {
                        WebConfigModification clonedWebConfigModification = webConfigModification.Clone();

                        string key = String.Format("{0}{1}{2}", webConfigModification.Path, webConfigModification.Path.EndsWith("/") ? "" : "/", webConfigModification.Name);

                        if (listViewApplied.Items[key] == null)
                        {
                            appliedWebConfigModifications.Add(clonedWebConfigModification);
                            PopulateListView(listViewApplied);
                        }       
                    }
                }

                #endregion
            }
            catch (Exception exception)
            {
                SetStatusError(exception.Message);
                ClearXmlDocument(true);
            }
        }

        private void pictureBoxApply_Click(object sender, EventArgs e)
        {
            if (((Control)sender).Name.EndsWith("1"))
            {
                listView_Enter(listViewApplied, new EventArgs());
            }
            else
            {
                listView_Enter(listViewToApply, new EventArgs());
            }

            if (xmlDocumentReady)
            {
                applyMenuItem_Click(this, new EventArgs());
            }
        }

        private void textBoxValue_DoubleClick(object sender, EventArgs e)
        {
            TextEditForm textEdit = new TextEditForm(textBoxValue.Text);
            textEdit.ShowDialog();
            textBoxValue.Text = textEdit.Text;
        }

        #endregion

        #region Private Methods

        private void ClearXmlDocument(bool withError)
        {
            if (withError)
            {
                webBrowserConfigFile.DocumentText = String.Format("<HTML><SPAN style='font-size:x-large;color:#86b3e0'>{0}</SPAN></HTML>", Constants.ErrorCouldNotLoadXml);
                xmlDocumentError = true;
            }
            else
            {
                webBrowserConfigFile.DocumentText = String.Empty;
                xmlDocumentError = false;
            }
        }

        private void DisplayXmlDocument(bool highLight)
        {
            StringBuilder styleTemplates = new StringBuilder();
            StringBuilder extraStyleTemplates = new StringBuilder();

            styleTemplates.Append(Properties.Resources.CollapsedStyleSheet);

            if (highLight)
            {
                int sequence = 50;

                if (toApplyWebConfigModifications != null)
                {
                    foreach (WebConfigModification webConfigModification in toApplyWebConfigModifications)
                    {
                        if (webConfigModification.Type == WebConfigModificationType.EnsureAttribute)
                        {
                            extraStyleTemplates.Append(String.Format("<xsl:template match=\"{0}[@{1}='{2}']\" priority=\"{3}\">", webConfigModification.Path, webConfigModification.Name, webConfigModification.Value, sequence++));
                        }
                        else
                        {
                            extraStyleTemplates.Append(String.Format("<xsl:template match=\"{0}/{1}\" priority=\"{2}\">", webConfigModification.Path, webConfigModification.Name, sequence++));
                        }
                        extraStyleTemplates.Append("<xsl:call-template name=\"highlighted\"/>");
                        extraStyleTemplates.Append("</xsl:template>");
                    }
                }

                styleTemplates.Replace("<!--extra-->", extraStyleTemplates.ToString());
            }

            byte[] xslBuffer = ASCIIEncoding.ASCII.GetBytes(styleTemplates.ToString());

            using (MemoryStream memoryStream = new MemoryStream(xslBuffer))
            {
                try
                {
                    XmlReader xmlReader = XmlReader.Create(memoryStream);
                    XslCompiledTransform xslCompiledTransform = new XslCompiledTransform();
                    xslCompiledTransform.Load(xmlReader);

                    StringBuilder xmlBuffer = new StringBuilder();
                    XmlWriter xmlWriter = XmlWriter.Create(xmlBuffer);
                    xslCompiledTransform.Transform(xmlDocument, xmlWriter);
                    webBrowserConfigFile.DocumentText = xmlBuffer.ToString();
                    xmlDocumentError = false;
                    ClearStatusMessage();
                }
                catch (Exception exception)
                {
                    SetStatusError(exception.Message);
                    xmlDocumentError = true;
                }
            }
        }

        private void ClearWebConfigModification()
        {
            textBoxOwner.Text = ConfigurationHelper.DefaultOwner;
            textBoxSequence.Text = "0";
            dropDownType.SelectedIndex = (int)WebConfigModificationType.EnsureChildNode;
            textBoxPath.Text = String.Empty;
            textBoxName.Text = String.Empty;
            textBoxValue.Text = String.Empty;
            textBoxPreviousAttributeValue.Text = String.Empty;

            buttonMofication.Text = buttonMofication.Text.Replace("&Save", "&Add");
        }

        private void DisplayWebConfigModification(WebConfigModification webConfigModification)
        {
            textBoxOwner.Text = webConfigModification.Owner;
            textBoxSequence.Text = webConfigModification.Sequence.ToString();
            dropDownType.Text = webConfigModification.Type.ToString();
            textBoxPath.Text = webConfigModification.Path;
            textBoxName.Text = webConfigModification.Name;
            textBoxValue.Text = webConfigModification.Value;
            textBoxPreviousAttributeValue.Text = webConfigModification.PreviousAttributeValue;

            buttonMofication.Text = buttonMofication.Text.Replace("&Add", "&Save");

            ValidateChildren();
        }

        private void ClearStatusMessage()
        {
            statusLabel.Text = String.Empty;
            statusLabelTimer.Stop();
        }

        private void SetStatusError(string errorMessage)
        {
            statusLabel.ForeColor = Color.Red;
            statusLabel.Text = errorMessage;
            statusLabelTimer.Start();
        }

        private void PopulateListView(ListView listView)
        {
            listIsLoading = true;

            listView.Items.Clear();

            List<WebConfigModification> webConfigModifications = null;

            if (listView.Equals(listViewApplied))
            {
                webConfigModifications = appliedWebConfigModifications;
            }
            else
            {
                webConfigModifications = toApplyWebConfigModifications;

                string label = "Add checked / remove unchecked from Already Applied.";
                ListViewItem listViewItem = listView.Items.Add(label, label, 0);
                listViewItem.Tag = "Fixed";
                listViewItem.Checked = true;
            }

            foreach (WebConfigModification webConfigModification in webConfigModifications)
            {
                string label = String.Empty;

                if (webConfigModification.Type == WebConfigModificationType.EnsureAttribute)
                {
                    label = String.Format("{0}[@{1}='{2}']", webConfigModification.Path, webConfigModification.Name, webConfigModification.Value);
                }
                else
                {
                    label = String.Format("{0}{1}{2}", webConfigModification.Path, webConfigModification.Path.EndsWith("/") ? "" : "/", webConfigModification.Name);
                }
                ListViewItem listViewItem = listView.Items.Add(label, label, webConfigModification.Checked ? 1 : 0);
                listViewItem.Checked = webConfigModification.Checked;
                listViewItem.StateImageIndex = listViewItem.Checked ? 1 : 0;
            }

            #region Update Details Link
            
            if (listView.Equals(listViewApplied))
            {
                listViewToApply.Refresh();
            }

            #endregion

            listIsLoading = false;
        }

        private void PopulateCurrentListView()
        {
            PopulateListView(currentListView);
        }

        #endregion

        private void dropDownType_SelectedIndexChanged(object sender, EventArgs e)
        {
            textBoxPreviousAttributeValue.Enabled = (dropDownType.Text == "EnsureAttribute");
        }

        private void buttonGenerateCode_Click(object sender, EventArgs e)
        {
            string generatedCode = String.Empty;
            string formattedCode = String.Empty;

            #region Prepare WebConfigModification Collections

            List<WebConfigModification> webConfigModificationsToRemove = SharePointUtilites.GetWebConfigModificationsForCodeGeneration(appliedWebConfigModifications, WebConfigModificationAction.Remove);
            List<WebConfigModification> webConfigModificationsToAdd = SharePointUtilites.GetWebConfigModificationsForCodeGeneration(toApplyWebConfigModifications, WebConfigModificationAction.Add);

            #endregion

            CodeColorizer codeColorizer = new CodeColorizer();

            if (dropDownLanguageSelector.Text == "C#")
            {

                TemplateCSharp textTemplate = new TemplateCSharp();
                textTemplate.Session = new Dictionary<string, object>();
                textTemplate.Session["WebConfigModificationsToRemove"] = webConfigModificationsToRemove;
                textTemplate.Session["WebConfigModificationsToAdd"] = webConfigModificationsToAdd;
                textTemplate.Initialize();
                generatedCode = textTemplate.TransformText();

                formattedCode = codeColorizer.Colorize(generatedCode, Languages.CSharp);
            }
            else 
            {
                TemplateVBNet textTemplate = new TemplateVBNet();
                textTemplate.Session = new Dictionary<string, object>();
                textTemplate.Session["WebConfigModificationsToRemove"] = webConfigModificationsToRemove;
                textTemplate.Session["WebConfigModificationsToAdd"] = webConfigModificationsToAdd;
                textTemplate.Initialize();
                generatedCode = textTemplate.TransformText();

                formattedCode = codeColorizer.Colorize(generatedCode, Languages.VbDotNet);
            }

            formattedCode = formattedCode.Replace("\t", "&nbsp;&nbsp;&nbsp;&nbsp;");

            webBrowserCode.DocumentText = formattedCode;
        }

        private void UpdateAutoLookup()
        {
            AutoCompleteStringCollection autoCompleteStringCollection = new AutoCompleteStringCollection();

            foreach (var item in WebConfigHelper.GetWebConfigNodes(this.xmlDocument))
            {
                autoCompleteStringCollection.Add(item.ToString());
            }

            textBoxPath.AutoCompleteCustomSource = autoCompleteStringCollection;

            autoCompleteStringCollection = new AutoCompleteStringCollection();

            foreach (var item in ConfigurationHelper.FrequentlyUsedNodeNames)
            {
                autoCompleteStringCollection.Add(item.ToString());
            }

            textBoxName.AutoCompleteCustomSource = autoCompleteStringCollection;
        }

        private void addWebConfigModificationMenuItem_Click(object sender, EventArgs e)
        {
            if (xmlDocumentError)
            {
                SetStatusError("Can not apply modifications if there was an error during the loading of the xml document.");
                return;
            }

            AddWebConfigModificationForm addWebConfigModificationForm = new AddWebConfigModificationForm(this.xmlDocument);
            DialogResult dialogResult = addWebConfigModificationForm.ShowDialog();

            if (dialogResult == DialogResult.OK)
            {
                currentWebConfigModifications.Add(addWebConfigModificationForm.WebConfigModification);
                PopulateCurrentListView();
            }
        }

        private void saveGeneratedCodeMenuItem_Click(object sender, EventArgs e)
        {
            saveFileDialog.DefaultExt = (dropDownLanguageSelector.Text == "C#") ? "cs": "vb";
            saveFileDialog.AddExtension = true;
            saveFileDialog.Filter = (dropDownLanguageSelector.Text == "C#") ? "C# Files (*.cs)|*.cs" : "Visual Basic Files (*.vb)|*.vb";
            DialogResult dialogResult = saveFileDialog.ShowDialog();

            if (dialogResult == DialogResult.OK)
            {
                try
                {
                    File.WriteAllText(saveFileDialog.FileName, webBrowserCode.Document.Body.InnerText);
                }
                catch (Exception exception)
                {
                    MessageBox.Show("Could not save generated code file.");
                    SetStatusError(exception.Message);
                }
            }
        }

        private void pictureBoxAdd_Click(object sender, EventArgs e)
        {
            addWebConfigModificationMenuItem_Click(sender, e);
        }

        private void dropDownLanguageSelector_SelectedIndexChanged(object sender, EventArgs e)
        {
            buttonGenerateCode_Click(sender, e);
        }

        private void getFromWebApplicationMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                if (dropDownWebApplications.Text != Constants.ErrorSharePointNotAvailable && dropDownWebApplications.Text != Constants.MessageWebApplicationsLoading)
                {
                    appliedWebConfigModifications.Clear();
                    appliedWebConfigModifications.AddRange(SharePointUtilites.GetWebConfigModifications(dropDownWebApplications.Text));
                    PopulateCurrentListView();

                    MessageBox.Show(String.Format("{0} modification{1} found for webapplication '{2}' in the configuration database.", (appliedWebConfigModifications.Count == 0) ? "No" : appliedWebConfigModifications.Count.ToString(), (appliedWebConfigModifications.Count == 1) ? String.Empty: "s", dropDownWebApplications.Text), "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
            catch (Exception exception)
            {   
                SetStatusError(exception.Message);
            }
        }

        private void listView_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Delete)
            {
                if (currentIndex > -1)
                {
                    currentWebConfigModifications.RemoveAt(currentIndex);
                    PopulateCurrentListView();
                    ClearWebConfigModification();
                }
            }
        }

        private void aboutMenuItem_Click(object sender, EventArgs e)
        {
            AboutForm aboutForm = new AboutForm();
            aboutForm.ShowDialog();
        }

       
        private void statusLabel_Click(object sender, EventArgs e)
        {
            if (!String.IsNullOrEmpty(statusLabel.Text))
            {
                MessageBox.Show(statusLabel.Text);
            }
        }

        private void viewHelpMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Currently help is provided by means of a blog article on www.digitude.net/blog.");
        }
    }
}
